//
//  Lattice.h
//  phi_four
//
//  Created by Snir Gazit on 3/8/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#ifndef Lattice_h
#define Lattice_h

#include "../HelpLibs/ArrayMultiD.h"
#include "../HelpLibs/def.h"

using namespace std;
using namespace boost;



enum MoveDir {
	RIGHT_ARROW = 0, LEFT_ARROW = 1
};

enum CreateRemove {
	CREATE = 0, REMOVE = 1
};


typedef int BondValType;
typedef boost::array<BondValType,NF> BondType;
struct Site {
	typedef ArrayMulti<Site, DIM> SiteArray;
	typedef SiteArray::iterator SiteArrayIterator;
	typedef SiteArray::IterIndex SiteArrayIndexIterator;
	typedef boost::array<BondType*, 2 * DIM> BondArray;
	typedef boost::array<SiteArrayIterator, 2 * DIM> NSiteArray;
	BondArray bondArray_;
	NSiteArray nSiteArray_;
	boost::array<BondValType,NF> totalBondsArray_;
	BondValType totalBonds_;
	friend class boost::serialization::access;
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & totalBondsArray_;
		ar & totalBonds_;
	}
};

struct Lattice {
	// Typedefs
	// XY Bonds
	typedef boost::array<BondType, DIM> BondData;
	typedef BondData::iterator BondDataVectorIterator;
	typedef Site::SiteArrayIterator SiteIter;
	typedef Site::SiteArrayIndexIterator SiteIterIndex;
	// Bond Array
	typedef ArrayMulti<BondData, DIM> BondArray;
	typedef BondArray::iterator BondArrayIter;
	// functions
	void init(IndexType const &latSize);
	void initSquare(IndexType const &latSize);
	SiteIter getSite(int distanceFromStart);
	boost::array<int, DIM> getSizes();
	void moveIraMasha(IndexType moveToPos);
	int getCordinationNumber() const;
	int getNumOfSites() const;
	// Debug Functions
	bool testConfiguration(int &totalBonds);
	// Measure Functions
	BondArrayIter BondBegin();
	BondArrayIter BondEnd();
	SiteIter siteBegin();
	SiteIter siteEnd();
	SiteIterIndex siteBeginIndex();
	SiteIterIndex siteEndIndex();
	IndexType iraIndex();
	IndexType mashaIndex();
	void dump(string fileName, bool final, ofstream *outFile);
	void read(string fileName);
	template<class Archive>
	void save(Archive & ar, const unsigned int version) const;
	template<class Archive>
	void load(Archive & ar, const unsigned int version);
	BOOST_SERIALIZATION_SPLIT_MEMBER();
	Site::SiteArray siteLattice_;
	BondArray BondLattice_;
	SiteIter ira_, masha_;
	boost::array<int, DIM> latSize_;
	int cordinationNumber_;
	int sectorType_;
	int totalBonds_;
	bool isClosed_;
};
template<class Archive>
void Lattice::save(Archive & ar, const unsigned int version) const {
	for (auto itb = BondLattice_.begin(); itb != BondLattice_.end(); itb++)
		for (auto itd = itb->begin(); itd != itb->end(); itd++)
			ar & *itd;
	for (auto itb = siteLattice_.begin(); itb != siteLattice_.end(); itb++)
		ar & *itb;
	int ira = ira_ - siteLattice_.begin();
	ar & ira;
	int masha = masha_ - siteLattice_.begin();
	ar & masha;
	ar & sectorType_;
	ar & totalBonds_;
}
template<class Archive>
void Lattice::load(Archive & ar, const unsigned int version) {
	for (auto itb = BondLattice_.begin(); itb != BondLattice_.end(); itb++)
		for (auto itd = itb->begin(); itd != itb->end(); itd++)
			ar & *itd;
	for (auto itb = siteLattice_.begin(); itb != siteLattice_.end(); itb++)
		ar & *itb;
	int ira;
	ar & ira;
	ira_ = this->siteBegin() + ira;
	int masha;
	ar & masha;
	masha_ = this->siteBegin() + masha;
	ar & sectorType_;
	ar & totalBonds_;
}
#endif
